package main

import "fmt"

// defer 函数在的应用场景

// 1、defer 的执行顺序。 采用栈的方式执行，先定义后执行。
// 2、defer 与 return 谁先谁后。return 之后的语句先执行，defer 后的语句后执行。
// 3、函数的返回值初始化与 defer 间接影响。defer中修改了返回值，实际返回的值是按照defer修改后的值进行返回。
// 4、defer 遇见 panic。按照defer的栈顺序，输出panic触发之前定义好的defer。
// 5、defer 中包含 panic。按照defer的栈顺序，输出panic触发之前的defer。并且defer中会接收到panic信息。
// 6、defer 下的函数参数包含子函数。会先进行子函数的结果值，然后在按照栈的顺序进行输出。

// 作者：小麦加油呀
// 链接：https://juejin.cn/post/7206195315925647420
// 来源：稀土掘金
// 著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。

func main() {
	defer4()
}

// 1. 直接使用
// defer在函数返回之前执行，defer后面跟着的是要执行的代码块
func defer1() {
	defer func() {
		fmt.Print("defer2")
	}()
	fmt.Print("defer1")
	fmt.Print("=>")
}

// 输出结果
// defer1=>defer2

// 2. defer 和 return 的使用。defer和return执行的顺序是先执行return后的语句，在执行defer语句，最后在执行return操作。
func defer2() int {
	defer func() {
		fmt.Println("2")
	}()
	return func() int {
		fmt.Println("1")
		return 4
	}()
}

// 1 -> 2 -> 4

// 遇见panic
// panic之前的defer会正常执行，并且是按照defer的执行顺序。
func defer3() {
	defer func() {
		fmt.Println("1")
	}()
	defer func() {
		fmt.Println("2")
	}()
	defer func() {
		fmt.Println("3")
	}()
	panic("panic")
	defer func() {
		fmt.Println("4")
	}()
}

// 输出结果
// 3 -> 2 -> 1

func defer4() {
	defer func() {
		fmt.Println("1")
		if err := recover(); err != nil {
			fmt.Println(err)
		}
	}()
	defer func() { fmt.Println("2") }()
	panic("panic")
	defer func() { fmt.Println("defer: panic 之后, 永远执行不到") }()
}

// 输出结果
// 2 -> 1 -> panic
